package cn.ilikes.tools.nosql.jpa.classloads.porxys;

import java.lang.reflect.Method;

import javax.persistence.PersistenceException;

import cn.ilikes.tools.nosql.jpa.clients.AbClient;
import cn.ilikes.tools.nosql.jpa.graphs.Node;
import cn.ilikes.tools.nosql.jpa.graphs.NodeLifeCycle.LifeCycle;
import cn.ilikes.tools.nosql.jpa.metadatas.EntityMetaData;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.EntityFields;
import cn.ilikes.tools.nosql.jpa.persistences.contexts.AbstractContext;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.NoOp;

public class CglibLayInitializerEntity implements LazyInitializers, InvocationHandler {

	private EntityMetaData entityMetaData;

	private Object keyId;

	private AbstractContext abstractContext;

	private Enhancer enhancer;

	public CglibLayInitializerEntity(final EntityMetaData entityMetaData, final Object keyId, AbstractContext abstractContext) {
		this.entityMetaData = entityMetaData;
		this.keyId = keyId;
		this.abstractContext = abstractContext;
		init();
	}

	private final CallbackFilter FINALIZE_FILTER = new CallbackFilter() {
		public int accept(Method method) {
			if (method.equals(entityMetaData.getEntityId().getSetMethod()) || method.getName().equals("finalize") || method.equals(entityMetaData.getEntityId().getGetMethod()))
				return 1;

			for (EntityFields entityFields : entityMetaData.getEntityFields().values()) {
				if (method.equals(entityFields.getSetMethod()) || method.equals(entityFields.getGetMethod()))
					return 0;
			}
			return 1;
		}
	};

	private void setEnhancer(Enhancer enhancer) {
		this.enhancer = enhancer;
	}

	private void init() {

		Enhancer e = new Enhancer();
		e.setSuperclass(entityMetaData.getEntityClazz());
		e.setInterfaces(entityMetaData.getInterfaces());
		e.setCallbackTypes(new Class[] { InvocationHandler.class, NoOp.class });
		e.setCallbackFilter(FINALIZE_FILTER);
		e.setCallbacks(new Callback[] { this, NoOp.INSTANCE });
		e.setUseFactory(false);
		e.setInterceptDuringConstruction(false);
		setEnhancer(e);

	}

	@Override
	public Object getProxy() throws PersistenceException {
		try {
			Object object = enhancer.create();
			Method method = entityMetaData.getEntityId().getSetMethod();
			method.invoke(object, keyId);
			return object;
		} catch (Exception e) {
			throw new PersistenceException(e);
		}
	}

	@Override
	public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
		Node node = abstractContext.getCache(keyId, entityMetaData);
		if (node == null || !node.getNodeLifeCycle().isLifeCycle(LifeCycle.managed)) {
			AbClient client = abstractContext.getClient();
			node = client.findById(entityMetaData, keyId);
			node.getNodeLifeCycle().setLifeCycle(LifeCycle.managed);
			abstractContext.putCache(keyId, node);
			//			Object  client.findValue(targetEntityMetaData, keyId, entityFields.getField().getType(), JPAUtils.getfamily(columnName, index), JPAUtils.getQualifier(columnName, index));	
			//			EntityFields entityFields = selectByMethod(method);
			//			String columnName = entityFields.getjPAField().getColumnName();
			//			int index = columnName.indexOf(SysConfigs.hbase_column_family_qualifier);

		}
		return method.invoke(node.getEntity(), arg2);
	}

}
